package org.jetbrains.plugins.scala.compiler

import com.intellij.openapi.project.Project
import org.jetbrains.jps.incremental.scala.remote.{CompileServerCommand, CompileServerMeteringInfo, CompileServerMetrics}
import org.jetbrains.jps.incremental.scala.{Client, DummyClient}
import org.jetbrains.plugins.scala.util.ScheduledService

import scala.concurrent.duration._

trait CompileServerClient {

  def execCommand(command: CompileServerCommand, client: Client): Unit

  final def withMetering(meteringInterval: FiniteDuration)(action: => Unit): CompileServerMeteringInfo = {
    val aggregator = new MetricsAggregator()

    val service = new ScheduledService(meteringInterval) {
      override def runnable: Runnable = () => {
        val metrics = getMetrics()
        aggregator.update(metrics)
      }
    }

    service.startScheduling()
    try {
      action
    } finally {
      service.stopScheduling()
    }

    aggregator.result()
  }

  final def getMetrics(): CompileServerMetrics = {
    val command = CompileServerCommand.GetMetrics
    var result: CompileServerMetrics = null
    val client = new DummyClient {
      override def metrics(value: CompileServerMetrics): Unit = result = value
      override def trace(exception: Throwable): Unit = throw exception
    }
    execCommand(command, client)
    if (result == null)
      throw new IllegalStateException("Compile server haven't return metrics")
    else
      result
  }
}

object CompileServerClient {

  def get(project: Project): CompileServerClient =
    project.getService(classOf[CompileServerClient])
}

class CompileServerClientImpl(project: Project)
  extends CompileServerClient {

  override def execCommand(command: CompileServerCommand, client: Client): Unit =
    new RemoteServerRunner()
      .buildProcess(command.id, command.asArgs, client)
      .runSync()
}
